#ifndef INDEXARRAY_H_
#define INDEXARRAY_H_

#include <string>
#include <set>
#include <vector>
#include "status.hxx"



class RandomAccessFile;
class IndexArrayMapping;

//the heder of the index array file
class IndexArrayHeader {

private:
	uint64_t m_version;
	uint64_t m_magic;

    //high water mark of update
	uint64_t m_hwm;

    //low water mark of update
	uint64_t m_lwm;

    //the number of elements
	uint32_t m_length;

    //the element isze, it is 8 
	uint32_t m_elemSize;
	
	
public:
	//IndexArrayHeader(){}
	IndexArrayHeader(int arrayLength, int elementSize);
    IndexArrayHeader();

	uint64_t getVersion() {
	    return m_version;
	  }
	  
	 uint64_t getLwmScn() {
	    return m_lwm;
	  }
	  
	  uint64_t getHwmScn() {
	    return m_hwm;
	  }
	  
	 uint32_t getArrayLength() {
	    return m_length;
	  }
	  
	  uint32_t getElementSize() {
	    return m_elemSize;
	  }

	 void setWaterMarks(long lwm, long hwm) {

	    m_lwm = lwm; m_hwm = hwm;
     }

     void getWaterMarks(uint64_t& lwm, uint64_t& hwm) {
     
        lwm = m_lwm; hwm = m_hwm;
     }

	std::string serialize();
	void deserialize(const std::string& data);

    std::string toString();
	bool checkHeader();
};

//a class manageing the access of a index array file
class IndexArrayFile {

private:
	std::string m_indexArrayFile;
	RandomAccessFile* m_raf; 
	IndexArrayHeader m_header;

    //memory buffer to hold index array
    uint64_t* m_iaBuf;
	

	static uint32_t INDEXARRAY_HEADER_LENGTH;
	static uint32_t INDEXDATA_START_OFFSET;

public:
	IndexArrayFile(const std::string& partitionPath, int arrayLength, int elementSize);
	IndexArrayFile(const std::string& partitionPath);
    ~IndexArrayFile();
	
	DbStatus loadHeader();
	DbStatus saveHeader();
    IndexArrayHeader getHeader() {return m_header;}
	
	DbStatus loadData();
	DbStatus saveData();

	DbStatus writeLong(uint32_t index, uint64_t value);  
	DbStatus flush();

	DbStatus init();
	
	void setWaterMarks(uint64_t lwm, uint64_t hwm) {
	
		m_header.setWaterMarks(lwm, hwm);
	}

    void getWaterMarks(uint64_t& lwm, uint64_t& hwm) {
    
        m_header.getWaterMarks(lwm, hwm);
    }

    uint64_t get(uint32_t index);
    void set(uint32_t index, uint64_t value, uint64_t scn);
    void set(uint32_t index, uint64_t value);

    //apply the update to index array file
    DbStatus applyEntries(IndexArrayMapping& entries);
	
private:

};

//a base class for index array. Will support static index array and dynamic
//index array
class IndexArray {

protected:
	uint32_t m_capacity;
	std::string m_partitionPath;
	IndexArrayFile* m_indexArrayFile;

    //the lastest entries is put in m_entries 
	IndexArrayMapping* m_entries; 

    //during sync, put the latest entries into the queue below, after flush log,
    //we can allpy the entries in the queue;
    std::vector<IndexArrayMapping*> m_entriesNotAppliedYet;
    
    //the lock to protect m_entriesNotAppliedYet
    pthread_mutex_t m_mutex;

public:
	IndexArray(const std::string& partitionPath, uint32_t indexArrayCapacity);
	virtual ~IndexArray();
	
	virtual DbStatus get(uint32_t index, uint64_t& value) = 0;
	virtual DbStatus set(uint32_t index, uint64_t value, uint64_t scn) = 0;
    virtual DbStatus set(uint32_t index, uint64_t value) = 0;

	virtual DbStatus init() = 0;
	virtual DbStatus flush() = 0;

	virtual void setWaterMarks(uint64_t lwm, uint64_t hwm) = 0;

    virtual void getWaterMarks(uint64_t& lwm, uint64_t& hwm) = 0;

    uint32_t getCapacity() {return m_capacity;}
    
    //should be called before writing log during sync
    virtual void switchEntries() = 0;
};

#endif
